/*
 * @copyright 2010 Gerald Jacobson
 * @license GNU General Public License
 * 
 * This file is part of My Quick Rules.
 *
 * My Quick Rules is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * My Quick Rules is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with My Quick Rules.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.amphiprion.myquickrules;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.amphiprion.myquickrules.entity.LocalGame;
import org.amphiprion.myquickrules.task.ImportGameRuleTask;
import org.amphiprion.myquickrules.task.ImportGameRuleTask.ImportRuleListener;
import org.amphiprion.myquickrules.task.LocalGamesTask;
import org.amphiprion.myquickrules.task.LocalGamesTask.LoadLocalGameListener;
import org.amphiprion.myquickrules.util.ApplicationConstants;
import org.amphiprion.myquickrules.util.GameRuleCheckerRunnable;
import org.amphiprion.myquickrules.util.GameRuleCheckerRunnable.GameRuleUpdateCheckerListener;
import org.amphiprion.myquickrules.view.LocalGameSummaryView;
import org.amphiprion.myquickrules.view.MyScrollView;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.SearchManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Rect;
import android.os.AsyncTask.Status;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewTreeObserver.OnScrollChangedListener;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ProgressBar;
import android.widget.TextView;

/**
 * @author amphiprion
 * 
 */
public class Home extends Activity implements LoadLocalGameListener, GameRuleUpdateCheckerListener {
	private static final int PAGE_SIZE = 10;
	private MyScrollView scrollView;
	private boolean allLoaded;
	private boolean loading;
	private String query;
	private List<LocalGame> games;
	private int loadedPage;
	private LocalGame current;
	private LocalGamesTask task;
	private Map<String, LocalGameSummaryView> ruleView;
	private SharedPreferences pref;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.local_game_list);

		createDefaultFiles();

		handleIntent(getIntent());

		scrollView = (MyScrollView) findViewById(R.id.scroll_view);
		scrollView.setOnScrollChanged(new OnScrollChangedListener() {
			@Override
			public void onScrollChanged() {
				if (!allLoaded && !loading) {
					LinearLayout ln = (LinearLayout) scrollView.getChildAt(0);
					if (ln.getChildCount() > 3) {
						Rect r = new Rect();
						boolean b = ln.getChildAt(ln.getChildCount() - 3).getLocalVisibleRect(r);
						if (b) {
							loading = true;
							loadNextPage();
						}
					}
				}
			}
		});

		pref = getSharedPreferences(ApplicationConstants.GLOBAL_PREFERENCE, 0);
		if (pref.getInt("HELP", 0) == 0) {
			showTimerHelp();
		} else {
			init();
		}
	}

	private void createDefaultFiles() {
		String state = Environment.getExternalStorageState();
		if (!Environment.MEDIA_MOUNTED.equals(state)) {
			// no SD card or in read only !
			// cannot create dirs and files
			return;
		}

		new File(Environment.getExternalStorageDirectory() + "/" + ApplicationConstants.DIRECTORY).mkdirs();
		File f = new File(Environment.getExternalStorageDirectory() + "/" + ApplicationConstants.DIRECTORY + "/games.xml");
		if (!f.exists()) {
			try {
				FileOutputStream fos = new FileOutputStream(f);
				fos.write("<games>\n\n</games>".getBytes());
				fos.close();
			} catch (Exception e) {
				Log.e(ApplicationConstants.PACKAGE, "", e);
			}
		}
		f = new File(Environment.getExternalStorageDirectory() + "/" + ApplicationConstants.DIRECTORY + "/read_me.txt");
		if (!f.exists()) {
			try {
				FileOutputStream fos = new FileOutputStream(f);
				fos.write(getResources().getString(R.string.read_me).getBytes());
				fos.close();
			} catch (Exception e) {
				Log.e(ApplicationConstants.PACKAGE, "", e);
			}

		}
		f = new File(Environment.getExternalStorageDirectory() + "/" + ApplicationConstants.DIRECTORY + "/xsd.zip");
		if (!f.exists()) {
			try {
				InputStream is = Home.class.getResourceAsStream("/xsd.zip");
				FileOutputStream fos = new FileOutputStream(f);
				byte[] b = new byte[4096];
				int len = 0;
				// int totalLen = 0;
				while ((len = is.read(b)) > 0) {
					// totalLen += len;
					fos.write(b, 0, len);
				}
				fos.close();
				is.close();
			} catch (Exception e) {
				Log.e(ApplicationConstants.PACKAGE, "", e);
			}
		}
	}

	@Override
	public boolean onSearchRequested() {
		startSearch(query, true, null, false);
		return true;
	}

	@Override
	protected void onNewIntent(Intent intent) {
		// setIntent(intent);
		handleIntent(intent);
	}

	private void handleIntent(Intent intent) {
		if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
			query = intent.getStringExtra(SearchManager.QUERY);
			init();
		}
	}

	private void init() {
		loadedPage = 0;
		LinearLayout ln = (LinearLayout) findViewById(R.id.local_game_list);
		ln.removeAllViews();
		ln.addView(getProgressView());
		if (games == null) {
			games = new ArrayList<LocalGame>();
			ruleView = new HashMap<String, LocalGameSummaryView>();
		} else {
			games.clear();
			ruleView.clear();
		}
		loadNextPage();
	}

	@Override
	protected void onSaveInstanceState(Bundle outState) {
		outState.putSerializable("GAMES", (Serializable) games);
		outState.putInt("PAGE", loadedPage);
		outState.putBoolean("ALL_LOADED", allLoaded);
		outState.putString("FILTER", query);
		outState.putInt("SCROLL_X", scrollView.getScrollX());
		outState.putInt("SCROLL_Y", scrollView.getScrollY());
	}

	@SuppressWarnings("unchecked")
	@Override
	protected void onRestoreInstanceState(Bundle savedInstanceState) {
		games = (List<LocalGame>) savedInstanceState.getSerializable("GAMES");
		loadedPage = savedInstanceState.getInt("PAGE");
		allLoaded = savedInstanceState.getBoolean("ALL_LOADED");
		query = savedInstanceState.getString("FILTER");
		if (task != null && task.getStatus() != Status.FINISHED) {
			task.cancel(true);
		}
		buildList();
		final int x = savedInstanceState.getInt("SCROLL_X");
		final int y = savedInstanceState.getInt("SCROLL_Y");
		scrollView.post(new Runnable() {
			@Override
			public void run() {
				scrollView.scrollTo(x, y);
			}
		});
	}

	private void loadNextPage() {
		// if (query != null && query.length() > 0) {
		task = new LocalGamesTask(this, query, games.size(), PAGE_SIZE);
		task.execute();
		// } else {
		// importEnded(true, null);
		// }
	}

	@Override
	protected void onDestroy() {
		if (task != null) {
			task.cancel(true);
		}
		super.onDestroy();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void importEnded(boolean succeed, List<LocalGame> newGames) {
		if (succeed) {
			task = null;
			if (newGames != null && newGames.size() > 0) {
				if (newGames.size() == PAGE_SIZE) {
					allLoaded = false;
				} else {
					allLoaded = true;
				}
			} else {
				allLoaded = true;
			}
			if (loadedPage != 0) {
				addElementToList(newGames);
			} else {
				games = newGames;
				buildList();
			}
			++loadedPage;
		} else {
			allLoaded = false;
			games = newGames;
			buildList();
		}
		loading = false;
	}

	/**
	 * File view with correct information, often a game list
	 */
	private void buildList() {
		String title = getResources().getString(R.string.app_name);
		if (query != null) {
			title += " [" + query + "]";
		}
		setTitle(title);

		LinearLayout ln = (LinearLayout) findViewById(R.id.local_game_list);
		ln.removeAllViews();
		if (games == null) {
			TextView tv = new TextView(this);
			tv.setText(R.string.null_game_list);
			ln.addView(tv);
		} else if (games.isEmpty()) {
			TextView tv = new TextView(this);
			tv.setText(R.string.empty_game_list);
			ln.addView(tv);
		} else {
			addElementToList(games);
		}
	}

	private void addElementToList(List<LocalGame> newGames) {
		LinearLayout ln = (LinearLayout) findViewById(R.id.local_game_list);
		if (newGames != games) {
			games.addAll(newGames);
			if (ln.getChildCount() > 0) {
				ln.removeViewAt(ln.getChildCount() - 1);
			}
		}
		GameRuleCheckerRunnable.setListener(this);
		for (final LocalGame game : newGames) {
			LocalGameSummaryView view = new LocalGameSummaryView(this, game);
			view.setOnClickListener(new View.OnClickListener() {
				@Override
				public void onClick(View v) {
					Intent i = new Intent(Home.this, ViewGameRules.class);
					i.putExtra("GAME", game);
					startActivity(i);
				}
			});
			view.setOnLongClickListener(new View.OnLongClickListener() {
				@Override
				public boolean onLongClick(View v) {
					registerForContextMenu(v);
					openContextMenu(v);
					unregisterForContextMenu(v);
					return true;
				}
			});
			ruleView.put(game.getId(), view);
			GameRuleCheckerRunnable.addCheck(game.getId());
			ln.addView(view);
		}

		if (!allLoaded) {
			ln.addView(getProgressView());
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.app.Activity#onActivityResult(int, int,
	 * android.content.Intent)
	 */
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		if (resultCode == RESULT_OK) {
			if (requestCode == ApplicationConstants.ACTIVITY_RETURN_ADD_GAME) {
				init();
			}
		}
	}

	private View getProgressView() {
		LinearLayout lnExpand = new LinearLayout(this);
		LayoutParams lp = new LayoutParams(android.view.ViewGroup.LayoutParams.FILL_PARENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
		lnExpand.setLayoutParams(lp);
		lnExpand.setBackgroundColor(getResources().getColor(android.R.color.black));

		ProgressBar im = new ProgressBar(this);
		LayoutParams imglp = new LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
		imglp.gravity = Gravity.CENTER_VERTICAL;
		imglp.rightMargin = 5;
		im.setLayoutParams(imglp);
		lnExpand.addView(im);

		TextView tv = new TextView(this);
		tv.setText(getResources().getText(R.string.loading));
		tv.setTextColor(getContext().getResources().getColor(android.R.color.white));
		LayoutParams tlp = new LayoutParams(android.view.ViewGroup.LayoutParams.FILL_PARENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT, 1);
		tlp.gravity = Gravity.CENTER_VERTICAL;

		tv.setLayoutParams(tlp);
		lnExpand.addView(tv);

		return lnExpand;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.app.Activity#onPrepareOptionsMenu(android.view.Menu)
	 */
	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		menu.clear();
		MenuItem addGameSheet = menu.add(0, ApplicationConstants.MENU_ID_ADD_GAME_SHEET, 0, R.string.add_game_sheet);
		addGameSheet.setIcon(android.R.drawable.ic_menu_add);
		return true;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
	 */
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		if (item.getItemId() == ApplicationConstants.MENU_ID_ADD_GAME_SHEET) {
			Intent i = new Intent(this, AvailableGameList.class);
			startActivityForResult(i, ApplicationConstants.ACTIVITY_RETURN_ADD_GAME);

		}
		return false;
	}

	@Override
	public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
		menu.clear();
		if (v instanceof LocalGameSummaryView) {
			current = ((LocalGameSummaryView) v).getLocalGame();
			menu.add(1, ApplicationConstants.MENU_ID_UPDATE_GAME_RULE, 0, R.string.update_game_rule);
			menu.add(1, ApplicationConstants.MENU_ID_SEND_MAIL, 1, R.string.send_mail);

		}
	}

	@Override
	public boolean onContextItemSelected(MenuItem item) {
		if (item.getItemId() == ApplicationConstants.MENU_ID_UPDATE_GAME_RULE) {
			ImportGameRuleTask iTask = new ImportGameRuleTask(new ImportRuleListener() {

				@Override
				public void importEnded(boolean succeed, final LocalGame newGame) {
					if (succeed) {
						final LocalGameSummaryView view = ruleView.get(newGame.getId());
						if (view != null && view.getLocalGame() != null) {
							runOnUiThread(new Runnable() {
								@Override
								public void run() {
									view.updateLocalGame(newGame);
								}
							});
						}
					}
				}

				@Override
				public Context getContext() {
					return Home.this;
				}
			}, current.getId());
			iTask.execute();
		} else if (item.getItemId() == ApplicationConstants.MENU_ID_SEND_MAIL) {
			sendMail(current);
		}
		return true;
	}

	private void sendMail(LocalGame lg) {
		final Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);

		emailIntent.setType("plain/text");
		emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[] { lg.mail });
		emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "MyGameRules: " + lg.getName());
		// emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, "");

		startActivity(Intent.createChooser(emailIntent, "Send mail..."));
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Context getContext() {
		return this;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.amphiprion.myquickrules.util.GameRuleCheckerRunnable.
	 * GameRuleUpdateCheckerListener#checked(java.lang.String, java.lang.String)
	 */
	@Override
	public void checked(String ruleId, final String availableVersion) {
		final LocalGameSummaryView view = ruleView.get(ruleId);
		if (view != null && availableVersion != null && view.getLocalGame() != null) {
			runOnUiThread(new Runnable() {
				@Override
				public void run() {
					view.setRepositoryVersion(availableVersion);
				}
			});
		}
	}

	private void showTimerHelp() {
		runOnUiThread(new Runnable() {

			@Override
			public void run() {
				AlertDialog.Builder builder = new AlertDialog.Builder(Home.this);
				builder.setMessage(getResources().getString(R.string.help));
				builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {

					@Override
					public void onClick(DialogInterface dialog, int which) {
						pref.edit().putInt("HELP", 1).commit();
						init();
					}
				});
				builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
					@Override
					public void onCancel(DialogInterface dialog) {
						finish();
					}
				});
				AlertDialog alert = builder.create();
				alert.show();
			}
		});

	}
}
